import os
import sys
import time
import hashlib
import ctypes
from ctypes import wintypes
from tkinter import messagebox

# 定义Windows API常量
PROCESS_TERMINATE = 0x0001
TH32CS_SNAPPROCESS = 0x00000002
INVALID_HANDLE_VALUE = -1
MAX_PATH = 260
CREATE_NO_WINDOW = 0x08000000

# 手动定义Windows结构体
class STARTUPINFO(ctypes.Structure):
    _fields_ = [
        ("cb", wintypes.DWORD),
        ("lpReserved", wintypes.LPWSTR),
        ("lpDesktop", wintypes.LPWSTR),
        ("lpTitle", wintypes.LPWSTR),
        ("dwX", wintypes.DWORD),
        ("dwY", wintypes.DWORD),
        ("dwXSize", wintypes.DWORD),
        ("dwYSize", wintypes.DWORD),
        ("dwXCountChars", wintypes.DWORD),
        ("dwYCountChars", wintypes.DWORD),
        ("dwFillAttribute", wintypes.DWORD),
        ("dwFlags", wintypes.DWORD),
        ("wShowWindow", wintypes.WORD),
        ("cbReserved2", wintypes.WORD),
        ("lpReserved2", wintypes.LPBYTE),
        ("hStdInput", wintypes.HANDLE),
        ("hStdOutput", wintypes.HANDLE),
        ("hStdError", wintypes.HANDLE),
    ]

class PROCESS_INFORMATION(ctypes.Structure):
    _fields_ = [
        ("hProcess", wintypes.HANDLE),
        ("hThread", wintypes.HANDLE),
        ("dwProcessId", wintypes.DWORD),
        ("dwThreadId", wintypes.DWORD),
    ]

class FILETIME(ctypes.Structure):
    _fields_ = [
        ("dwLowDateTime", wintypes.DWORD),
        ("dwHighDateTime", wintypes.DWORD),
    ]

class WIN32_FILE_ATTRIBUTE_DATA(ctypes.Structure):
    _fields_ = [
        ("dwFileAttributes", wintypes.DWORD),
        ("ftCreationTime", FILETIME),
        ("ftLastAccessTime", FILETIME),
        ("ftLastWriteTime", FILETIME),
        ("nFileSizeHigh", wintypes.DWORD),
        ("nFileSizeLow", wintypes.DWORD),
    ]

class PROCESSENTRY32(ctypes.Structure):
    _fields_ = [
        ("dwSize", wintypes.DWORD),
        ("cntUsage", wintypes.DWORD),
        ("th32ProcessID", wintypes.DWORD),
        ("th32DefaultHeapID", ctypes.POINTER(wintypes.ULONG)),
        ("th32ModuleID", wintypes.DWORD),
        ("cntThreads", wintypes.DWORD),
        ("th32ParentProcessID", wintypes.DWORD),
        ("pcPriClassBase", wintypes.LONG),
        ("dwFlags", wintypes.DWORD),
        ("szExeFile", ctypes.c_char * MAX_PATH)
    ]

# 加载Windows API函数
kernel32 = ctypes.WinDLL('kernel32', use_last_error=True)

CreateProcessW = kernel32.CreateProcessW
CreateProcessW.argtypes = [
    wintypes.LPCWSTR, wintypes.LPWSTR, wintypes.LPVOID, wintypes.LPVOID,
    wintypes.BOOL, wintypes.DWORD, wintypes.LPVOID, wintypes.LPCWSTR,
    ctypes.POINTER(STARTUPINFO),
    ctypes.POINTER(PROCESS_INFORMATION)
]
CreateProcessW.restype = wintypes.BOOL

OpenProcess = kernel32.OpenProcess
OpenProcess.argtypes = [wintypes.DWORD, wintypes.BOOL, wintypes.DWORD]
OpenProcess.restype = wintypes.HANDLE

TerminateProcess = kernel32.TerminateProcess
TerminateProcess.argtypes = [wintypes.HANDLE, wintypes.UINT]
TerminateProcess.restype = wintypes.BOOL

CloseHandle = kernel32.CloseHandle
CloseHandle.argtypes = [wintypes.HANDLE]
CloseHandle.restype = wintypes.BOOL

CreateToolhelp32Snapshot = kernel32.CreateToolhelp32Snapshot
CreateToolhelp32Snapshot.argtypes = [wintypes.DWORD, wintypes.DWORD]
CreateToolhelp32Snapshot.restype = wintypes.HANDLE

Process32First = kernel32.Process32First
Process32First.argtypes = [wintypes.HANDLE, ctypes.POINTER(PROCESSENTRY32)]
Process32First.restype = wintypes.BOOL

Process32Next = kernel32.Process32Next
Process32Next.argtypes = [wintypes.HANDLE, ctypes.POINTER(PROCESSENTRY32)]
Process32Next.restype = wintypes.BOOL

GetExitCodeProcess = kernel32.GetExitCodeProcess
GetExitCodeProcess.argtypes = [wintypes.HANDLE, ctypes.POINTER(wintypes.DWORD)]
GetExitCodeProcess.restype = wintypes.BOOL

WaitForSingleObject = kernel32.WaitForSingleObject
WaitForSingleObject.argtypes = [wintypes.HANDLE, wintypes.DWORD]
WaitForSingleObject.restype = wintypes.DWORD

GetFileAttributesExW = kernel32.GetFileAttributesExW
GetFileAttributesExW.argtypes = [wintypes.LPCWSTR, wintypes.INT, ctypes.POINTER(WIN32_FILE_ATTRIBUTE_DATA)]
GetFileAttributesExW.restype = wintypes.BOOL

class TaskManager:
    def __init__(self):
        self.target_task_names = []
        self.target_task_file = "targets.xpt"
        self.password_hash = "ce8d166d804e84c143cc4c1d5eb370dcc8ec0446c0789ee373f9f20994544586"
        self.last_modified = 0
        self.password_checked = False
        self.keeper_task = "xptkeeper.exe"
        self._start_keeper_task()

    def _start_keeper_task(self):
        """启动守护进程（如果尚未运行）"""
        if not self._is_process_running(self.keeper_task):
            startup_info = STARTUPINFO()
            startup_info.cb = ctypes.sizeof(STARTUPINFO)
            process_info = PROCESS_INFORMATION()
            
            # 将进程名转换为宽字符串
            keeper_task_wide = ctypes.c_wchar_p(self.keeper_task)
            
            # 使用CREATE_NO_WINDOW标志隐藏窗口
            success = CreateProcessW(
                None,  # 应用程序名
                keeper_task_wide,  # 命令行
                None, None, False,  # 安全属性
                CREATE_NO_WINDOW,  # 创建标志
                None, None,  # 环境和当前目录
                ctypes.byref(startup_info),
                ctypes.byref(process_info)
            )
            
            if success:
                CloseHandle(process_info.hThread)
                CloseHandle(process_info.hProcess)
            elif len(sys.argv) > 1 and sys.argv[1] == "debug":
                last_error = ctypes.GetLastError()
                messagebox.showerror("Error", f"启动守护进程失败: 错误代码 {last_error}")

    def _is_process_running(self, process_name):
        """检查指定进程是否正在运行"""
        hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0)
        if hSnapshot == INVALID_HANDLE_VALUE:
            return False
        
        pe32 = PROCESSENTRY32()
        pe32.dwSize = ctypes.sizeof(PROCESSENTRY32)
        
        if not Process32First(hSnapshot, ctypes.byref(pe32)):
            CloseHandle(hSnapshot)
            return False
        
        process_running = False
        while True:
            try:
                current_name = pe32.szExeFile.decode('utf-8', 'ignore').lower()
                if current_name == process_name.lower():
                    process_running = True
                    break
            except:
                pass
            
            if not Process32Next(hSnapshot, ctypes.byref(pe32)):
                break
        
        CloseHandle(hSnapshot)
        return process_running

    def _terminate_keeper(self):
        """终止守护进程"""
        return self._terminate_process_by_name(self.keeper_task)

    def _terminate_process_by_name(self, process_name):
        """通过进程名终止进程"""
        hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0)
        if hSnapshot == INVALID_HANDLE_VALUE:
            return False
        
        pe32 = PROCESSENTRY32()
        pe32.dwSize = ctypes.sizeof(PROCESSENTRY32)
        
        if not Process32First(hSnapshot, ctypes.byref(pe32)):
            CloseHandle(hSnapshot)
            return False
        
        terminated = False
        while True:
            try:
                current_name = pe32.szExeFile.decode('utf-8', 'ignore').lower()
                if current_name == process_name.lower():
                    hProcess = OpenProcess(PROCESS_TERMINATE, False, pe32.th32ProcessID)
                    if hProcess:
                        TerminateProcess(hProcess, 1)
                        CloseHandle(hProcess)
                        terminated = True
            except:
                pass
            
            if not Process32Next(hSnapshot, ctypes.byref(pe32)):
                break
        
        CloseHandle(hSnapshot)
        return terminated

    def _force_kill(self, pid):
        """强制终止指定PID的进程"""
        hProcess = OpenProcess(PROCESS_TERMINATE, False, pid)
        if not hProcess:
            return False
        
        # 尝试正常终止
        if not TerminateProcess(hProcess, 1):
            CloseHandle(hProcess)
            return False
        
        # 等待进程结束
        WaitForSingleObject(hProcess, 1000)
        CloseHandle(hProcess)
        return True

    def _load_target_task_from_file(self):
        try:
            if not os.path.exists(self.target_task_file):
                self.target_task_names = ["taskmgr.exe"]
                return
            
            # 使用Windows API获取文件修改时间
            file_attr = WIN32_FILE_ATTRIBUTE_DATA()
            file_path = ctypes.c_wchar_p(self.target_task_file)
            
            # 使用0作为第二个参数(GetFileExInfoStandard)
            if GetFileAttributesExW(file_path, 0, ctypes.byref(file_attr)):
                mod_time = file_attr.ftLastWriteTime
                mod_time_value = (mod_time.dwHighDateTime << 32) | mod_time.dwLowDateTime
                
                if mod_time_value <= self.last_modified:
                    return
                
                self.last_modified = mod_time_value
            else:
                # API失败时使用os模块回退
                self.last_modified = os.path.getmtime(self.target_task_file)
            
            with open(self.target_task_file, 'r', encoding='utf-8') as target_file:
                new_targets = []
                for line in target_file:
                    line = line.strip().lower()
                    if line:
                        if not line.endswith('.exe'):
                            line += '.exe'
                        new_targets.append(line)
                
                if new_targets != self.target_task_names:
                    self.target_task_names = new_targets
        except Exception as e:
            if len(sys.argv) > 1 and sys.argv[1] == "debug":
                messagebox.showerror("Error", f"配置文件错误: {str(e)}")

    def _check_password(self):
        try:
            if not os.path.exists("password.txt"):
                return False
            
            with open("password.txt", "r") as passwd_file:
                passwd = passwd_file.read().strip()
                if not passwd:
                    return False
                
                sha_256 = hashlib.sha256()
                sha_256.update(passwd.encode('utf-8'))
                if sha_256.hexdigest() == self.password_hash:
                    os.remove("password.txt")
                    return True
        except Exception as e:
            if len(sys.argv) > 1 and sys.argv[1] == "debug":
                messagebox.showerror("Error", f"密码验证错误: {str(e)}")
        return False

    def _handle_special_process(self, proc_name, pid):
        try:
            if proc_name.lower() == "xpte.exe":
                self._force_kill(pid)
                if not self.password_checked:
                    self.password_checked = True
                    if len(sys.argv) > 1 and sys.argv[1] == "debug":
                        messagebox.showinfo("Info", "检测到退出进程, 请在password.txt中输入密码")
                return True
        except Exception:
            pass
        return False

    def get_all_processes(self):
        """获取所有进程列表 (进程名, PID)"""
        processes = []
        hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0)
        if hSnapshot == INVALID_HANDLE_VALUE:
            return processes
        
        pe32 = PROCESSENTRY32()
        pe32.dwSize = ctypes.sizeof(PROCESSENTRY32)
        
        if not Process32First(hSnapshot, ctypes.byref(pe32)):
            CloseHandle(hSnapshot)
            return processes
        
        while True:
            try:
                proc_name = pe32.szExeFile.decode('utf-8', 'ignore')
                processes.append((proc_name.lower(), pe32.th32ProcessID))
            except:
                pass
            
            if not Process32Next(hSnapshot, ctypes.byref(pe32)):
                break
        
        CloseHandle(hSnapshot)
        return processes

    def run(self):
        while True:
            try:
                # 动态重载配置文件
                self._load_target_task_from_file()
                
                # 检查密码文件
                if os.path.exists("password.txt"):
                    if self._check_password():
                        # 终止守护进程
                        if self._terminate_keeper():
                            if len(sys.argv) > 1 and sys.argv[1] == "debug":
                                messagebox.showinfo("Info", "守护进程已终止")
                        if len(sys.argv) > 1 and sys.argv[1] == "debug":
                            messagebox.showinfo("Info", "密码验证成功，程序退出")
                        sys.exit(0)
                    else:
                        try:
                            os.remove("password.txt")  # 删除无效密码文件
                        except:
                            pass
                
                # 获取所有进程
                all_processes = self.get_all_processes()
                
                # 处理特殊进程和目标进程
                for proc_name, pid in all_processes:
                    # 先处理特殊进程
                    if self._handle_special_process(proc_name, pid):
                        continue
                    
                    # 普通目标进程
                    if proc_name in self.target_task_names:
                        self._force_kill(pid)
                
                time.sleep(1)
                
            except KeyboardInterrupt:
                if len(sys.argv) > 1 and sys.argv[1] == "debug":
                    messagebox.showinfo("Info", "想要退出程序请创建xpte.exe进程")
            except Exception as e:
                if len(sys.argv) > 1 and sys.argv[1] == "debug":
                    messagebox.showerror("Error", f"运行时错误: {str(e)}")
                time.sleep(5)

if __name__ == '__main__':
    TM = TaskManager()
    TM.run()